#include "SingleGraphClusterer.hpp"
#include "../../GraphPredicates.hpp"

#include <fstream>
#include <iostream>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/graph/copy.hpp>


using namespace boost::iostreams::gzip;
using namespace boost::iostreams;

std::map<GraphHandler::Vertex, int> SingleGraphClusterer::ClusterGraph(const GraphHandler::Graph& G)
{
    using namespace std;

    remove("tmp.edges.gz");

    ofstream edgefile("tmp.edges", ios_base::out);

    GraphHandler::Instance().SaveGraph("graph.dot", G);

    //system ("dot -Tpng graph.dot -o graph.png");

    edgefile << "edge\t" << "from\t" << "to\t" << "weight" << endl;

    int i=0;
    graph_traits<GraphHandler::Graph>::edge_iterator firstE, lastE;
    // For each edge
    for (tie(firstE, lastE) = edges(G); firstE != lastE; ++firstE)
    {
        if( boost::target(*firstE, G) != boost::source(*firstE, G) )
        {
            //edgefile << i << '\t' << get(vertex_name, G, boost::source(*firstE, G)) <<
            //            '\t' << get(vertex_name, G, boost::target(*firstE, G)) << "\t1" << endl;
            edgefile << i << '\t' << boost::source(*firstE, G) <<
                        '\t' << boost::target(*firstE, G) << "\t1" << endl;

            i++;
            edgefile << i << '\t' << boost::target(*firstE, G) <<
                        '\t' <<boost::source(*firstE, G) << "\t1" << endl;
            i++;
        }
    }

    system ("gzip tmp.edges");


    edgefile.flush();
    edgefile.close();


    // 2. Save vertices
    remove("tmp.vertices.gz");

    ofstream vertexfile("tmp.vertices", ios_base::out);

    vertexfile << "idx\tvertex-names\tvertex-weights" << endl;

    //idx	vertex-names	vertex-weights
    GraphHandler::Iter_t vi, vi_end;
    // For each vertex
    for (tie(vi, vi_end) = vertices(G); vi != vi_end; ++vi)
    {
         //cout << "Vertex: " << *vi << ", " << get(vertex_name, G, *vi) << endl;
        //vertexfile << get(vertex_name, G, *vi) << '\t' << G[*vi].sName << "\t1" << endl;
        //vertexfile << get(vertex_name, G, *vi) << '\t' << "test" << "\t1" << endl;
        vertexfile << *vi << '\t' << "test" << "\t1" << endl;
        i++;
    }

    system ("gzip tmp.vertices");

    //system ("../mlclustering/ml_modularity tmp.edges.gz");
    system ("../thirdparty/mlclustering/ml_modularity tmp.edges.gz");


    // Now read the result

    remove("result");

    system ("gunzip result.gz");

    ifstream in("result");

    string sTmp;
    getline(in, sTmp, '\n');

    std::map<GraphHandler::Vertex, int> kClusterMap;

    GraphHandler::SubGraph GRoot;
    copy_graph(G, GRoot);

    assert(num_vertices(G)==num_vertices(GRoot));
    assert(num_edges(G)==num_edges(GRoot));
   // GRoot = GRoot.create_subgraph(vi, vi_end);

    ofstream dotfile("tmpcluster.dot", ios_base::out);

    dotfile << "graph G {" << endl;
    //GraphHandler::SubGraph& G1 = GSubgraph.create_subgraph();

    // Store all the clusters
    std::map<int, GraphHandler::SubGraph*> kSubgraphs;

    bool bEndPar = false;
    int iClusterCount = 0;
    Vertex_writer vWriter(G);
    for (string row; getline(in, row, '\n'); )
    {

        istringstream ss(row);


        int iVertex, iCluster;

        string sTmp;

        getline(ss, sTmp, '\t');
        iVertex = lexical_cast<int>(sTmp);

        getline(ss, sTmp, '\t');
        iCluster = lexical_cast<int>(sTmp);

        if( kSubgraphs.find(iCluster) == kSubgraphs.end() )
        {
            kSubgraphs[iCluster] = &GRoot.create_subgraph();
            if( bEndPar )
                dotfile << "}\n";
            dotfile << "subgraph cluster" << iClusterCount << " {\n";
            bEndPar = true;
            iClusterCount++;
            cout << "New cluster " << iCluster << endl;
        }


        GraphHandler::Vertex vTmp = iVertex; //GraphHandler::Instance().FindVertex(iVertex, G).second;
        add_vertex(vTmp, *kSubgraphs[iCluster]);


       // dotfile << vTmp << "[label=\"" << G[vTmp].sName << "\"];\n";
        dotfile << vTmp;
        vWriter.operator ()(dotfile, vTmp);
        dotfile << "\n";

    }
    if( bEndPar )
        dotfile << "}\n";



    for (tie(firstE, lastE) = edges(G); firstE != lastE; ++firstE)
    {
        dotfile << boost::source(*firstE, G) << "--"  << boost::target(*firstE, G) << " ;\n";
    }

    dotfile << "}\n";



    return kClusterMap;





}
